#!/usr/bin/env python

# ---------------------------------------------------------------------
#  mommabot.py
#  starting nice and fresh
#----------------------------------------------------------------------
import re
import random
import nltk, re, pprint
import numpy
from nltk.corpus import brown
import Recipe
from nltk.corpus import wordnet as wn
import parser
import classifier
import string

############################ CLASS DECLERATIONS ################################ 

class UserState (object):
	def __init__(self):
		pass
		

class Search_state (object):
	def __init__(self, method, obj):
		self.method = method
		self.obj_list = list()
		self.curr_obj = ""
		self.filterHistory = list()
		self.seekingObj = False
		self.phase = 1
		self.last_num = -1 # saves the number of the last recipe viewed during phase 2
		self.rec = None
		self.last_filter = 0

	def seekingMethod(self):
		if self.method == "":
			return True
		else:
			return False
	
	def resetObjList(self):
		self.obj_list = []
	
	def resetMethod(self):
		self.method = ""
	
	def resetAll(self):
		self.resetObjList()
		self.resetMethod()
		self.seekingObj = False
	
	def resetComplete(self):
		self.resetAll()
		self.phase = 1
		self.last_num = 1
		self.last_filter = 0
		self.curr_obj = ""
		self.filterHistory = []
		
	def addFilter(self):
		self.filterHistory.append((self.method,self.curr_obj))
		#print "---added the filter ("+self.filterHistory[len(self.filterHistory)-1][0] + ", " + self.filterHistory[len(self.filterHistory)-1][1] + ") to the filter history"
		return
	
	def hasFilterHist(self):
		return len(self.filterHistory) > 0

########################## GLOBAL VARIABLES ##################################

cookBook = Recipe.CookBook()
current_search_state = Search_state("", "")
parse = parser.Parser()
user = UserState()
targetNumber = 5 


number_meaning = {}
number_meaning['one'] = 1
number_meaning['1'] = 1
number_meaning['first'] = 1
number_meaning['two'] = 2
number_meaning['2'] = 2
number_meaning['second'] = 2
number_meaning['three'] = 3
number_meaning['3'] = 3
number_meaning['third'] = 3
number_meaning['four'] = 4
number_meaning['4'] = 4
number_meaning['fourth'] = 4
number_meaning['five'] = 5
number_meaning['5'] = 5
number_meaning['fifth'] = 5
number_meaning['six'] = 6
number_meaning['6'] = 6
number_meaning['sixth'] = 6

exit_responses = ["I was fucking with you, that was rat meat!", "Do you have any heroin?", "Could you spare $500?", "Now get out of here, it's time for Mommy to take her meds and fuck your father."]

############################ NLP AND NLG ################################
def form_response_phase1(s): 
	# Work Flow
	# 1: search_state: get search_method and search_obj
	# 2: filter: update search_state
	# 3: checkpoint: if(simplest) -> #4 or if(continue refining) -> #2
	# 4: print recipe: (prompt user for stand-by or step-by-step presentation
	
	########################## RESPONSE GENERATION ###############################
	
	responseFound = False
	printPrompt = False
					

	if s == "phase3":
		return "phase3"
	if s == "showposs":
		print cookBook.printPossibilities()
		return

	if classify (s,'quit'): return "exit"
	
	if classify (s, 'startover'):
		restartMomma()
		responseFound = True
		printPrompt = True

	if classify (s, 'simplest'):
		rec = cookBook.simplest()
		name = rec.name
		print "Ok. We'll go with the simplest recipe: "+name
		current_search_state.method = "title"
		current_search_state.obj_list = [name]
		filterRecipes()
		current_search_state.rec = rec
		parser.rec = current_search_state.rec
		current_search_state.phase = 3
		print "Ok. Now I can show you the recipe or walk you through the recipe"
		responseFound = True

	parse.sentence = s
	nouns_list = parse.parse()
	sentence = parse.sentence_list

	if classify (s,'method'):
		if classify(s, 'title'): current_search_state.method = 'title'
		elif classify(s, 'category'): current_search_state.method = 'category'
		elif classify(s, 'ingredients'): current_search_state.method = 'ingredients'
		responseFound = True
		current_search_state.seekingObj = True
		print current_search_state.method


	
	# now, check if the the user is providing an object
	if not responseFound:
		for item in sentence:
			word = item.lower()
			if current_search_state.seekingObj == True and word in nouns_list: 
				current_search_state.obj = word
				current_search_state.obj_list.append(word)
				#print "Object = "+word
				responseFound = True
			
	# tell the user what information is missing
	if responseFound == False or printPrompt == True:
		if responseFound == False: print "I'm not sure what you mean..."
		if len(current_search_state.method) == 0:
			print "How would you like to search for recipes, by title, category, or ingredient?"
		elif len(current_search_state.obj_list) == 0:
			print "What " + current_search_state.method + " would you like to look for?"



	
	if len(current_search_state.obj_list) != 0:
		if current_search_state.phase == 1:
			tmp = "Okay, I'm looking for a "+ current_search_state.method
			tmp += " that matches "

			length = len(current_search_state.obj_list)
			i = 1
			for obj in current_search_state.obj_list:
				tmp += obj
				if not i == length: tmp += " and "
				i += 1
		filterRecipes();
		possLeft = len(cookBook.possibilities)
		if (possLeft == 0): 
			tmpCookBook = Recipe.CookBook()
			print "Unfortunately, I could find anything in our list where:"
			last_filter = current_search_state.last_filter
			oldFilters = current_search_state.filterHistory
			totalFilters = len(oldFilters)
			for i in range(totalFilters-last_filter,totalFilters):
				print "     "+current_search_state.filterHistory[i][0]+" matches "+current_search_state.filterHistory[i][1]
			current_search_state.filterHistory = []
			cookBook.possibilities = tmpCookBook.recipes
			for i in range(0,totalFilters-last_filter):
				current_search_state.method = oldFilters[i][0]
				current_search_state.obj_list = [oldFilters[i][1]]
				filterRecipes()
			print "let's try again! We still have "+str(len(cookBook.possibilities))+" items on our list. How would you like me to narrow those?"
		else:
			print "Okay. We've searched for all the recipes where:"
			for f in current_search_state.filterHistory:
				print "    " + f[0] + " matches " + f[1]
			if (possLeft > targetNumber):
				#cookBook.printPossibilities()
				print "\nI found " + str(possLeft) + " possibilities,so we need to filter the results more"
			elif possLeft == 1:
				print cookBook.printPossibilities()
				print "I can show you the recipe, we can just go for it, or we can start the whole thing from the beginning. What would you like to do?"
				current_search_state.phase = 2
			else:
				print "\nWe're down to " + str(possLeft) + " matching recipes. Here they are:"
				print cookBook.printPossibilities()
				print "\nI can show you any of those if you'd like, I can give you the simplest one, or you can just choose one."
				current_search_state.phase = 2


def restartMomma():
	tmpCookBook = Recipe.CookBook()
	cookBook.possibilities = tmpCookBook.recipes
	current_search_state.resetComplete()

def filterRecipes():
	if len(current_search_state.method) > 0 and len(current_search_state.obj_list) > 0:
		current_search_state.last_filter = 0
		for item in current_search_state.obj_list: 
			current_search_state.curr_obj = item
			current_search_state.addFilter()
			cookBook.filter(current_search_state.method, item)
			current_search_state.last_filter +=1
		#print "--- filter history:"
		#print current_search_state.filterHistory
		current_search_state.resetObjList()
	else:
		print "not enough information to search for a recipe (don't have method and object)"

def form_response_phase2(s):
	
	responseFound = False
	printPrompt = False
	
	# check for special input

	
	if classify (s,'quit'): return "exit"

	if classify (s, 'startover'):
		print "Ok. Let's start from the beginning."
		restartMomma()
		responseFound = True
		printPrompt = True
	
	num = -1
	match = classify (s,'number')
	if match:
		num = number_meaning[match.group(2)]
		possLeft = len(cookBook.possibilities)
		if num > possLeft:
			print "Sorry, there is no number " + str(num) + ". Please choose one from the list"
			num = -1
			responseFound = True
		else:
			name = cookBook.recipe(num).name
	
	if classify (s, 'show'):
		if num > 0:
			print "Ok. Here's recipe number " + str(num) + " ( " + name + ")"
			rec = cookBook.recipe(name)
			print rec.pretty_print()
			print "Would you like to go with that one, or a different one from the list? Or would you"
			print "like to see another one?"
			responseFound = True
			
	
	if classify	(s, 'select'):
		if num > 0:
			print "Ok! Let's go with " + name
			print "Let's get cooking!"
			current_search_state.method = "title"
			current_search_state.obj_list = [name]
			filterRecipes()
			current_search_state.rec = cookBook.recipe(name)
			parser.rec = current_search_state.rec
			current_search_state.phase = 3
			print "Ok. Now I can walk you through the recipe, or stand by for questions"
			responseFound = True

	if classify (s, 'options'):
		print cookBook.printPossibilities()
		print "I can show you any of those if you'd like, I can choose the simplest one for you, or you can just choose one."
		responseFound = True
	
	if classify (s, 'simplest'):
		rec = cookBook.simplest()
		name = rec.name
		print "Ok. We'll go with the simplest recipe: "+name
		current_search_state.method = "title"
		current_search_state.obj_list = [name]
		filterRecipes()
		current_search_state.rec = rec
		parser.rec = current_search_state.rec
		current_search_state.phase = 3
		print "Ok. Now I can show you the recipe or walk you through the recipe"
		responseFound = True
	
	if classify (s, 'this'):
		if current_search_state.last_num > 0:
			num = current_search_state.last_num
			name = cookBook.recipe(num).name
			if classify (s, 'select'):
				print "Ok! Let's go with " + name
				current_search_state.method = "title"
				current_search_state.obj_list = [name]
				filterRecipes()
				current_search_state.rec = cookBook.recipe(name)
				parser.rec = current_search_state.rec
				current_search_state.phase = 3
				print "Ok. Now I can walk you through the recipe, or stand by for questions"
				responseFound = True
			elif classify (s, 'show'):
				rec = cookBook.recipe(name)
				print rec.pretty_print()
				print "\nWould you like to go with that one, or a different one from the list? Or would you"
				print "like to see another one?"
				responseFound = True
	
	if num > 0: 
		current_search_state.last_num = num
			
	if not responseFound:
		if num > 0:
			print "I'm not sure what you mean, do you want to see number " + str(num) + ", or do you want to select it?"
		else:
			print "I can show you your options again, or you can look at or select any recipe from the list, or"
			print "I can offer the simplest one if you'd like"



def form_response_phase3(s):
	
	# check for special input
	if s == "phase3":
		return "phase3"
	
	if classify (s,'quit'): return "exit"
		
	if classify (s, 'startover'):
		print "Ok. Let's start from the beginning."
		restartMomma()
		responseFound = True
		printPrompt = True
	
	#print "--- We are in phase 3",
	rec = cookBook.recipe(1)
	#print " making " + rec.name
	parse.sentence = s.lower()
	print parse.formResponse(rec)

def classify(s,t):
	return  classifier.classify(s,t)




########################### COMMAND INTERFACE ###############################

def command_interface():
	s = ""
	f = open("driver.txt", 'r')

	while True:
		s = ""
		try:
			s = f.readline().rstrip()
			if len(s) == 0:
				exit()


			if current_search_state.phase == 1: ret = response = form_response_phase1(s)
			elif current_search_state.phase == 2: ret = response = form_response_phase2(s)
			elif current_search_state.phase == 3: ret = response = form_response_phase3(s)

			if ret == "phase3":
				num = random.randint(1,200)
				name = cookBook.recipe(num).name
				current_search_state.method = "title"
				current_search_state.obj_list = [name]
				filterRecipes()
				current_search_state.phase = 3
				name = cookBook.recipe(1).name
				print name
				parser.rec = cookBook.recipe(name)

		except EOFError:
			s = "quit"
			print (s)

if __name__ == "__main__":
	command_interface()

